home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs609s.zoo / minixfs / cache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-25  |  8.1 KB  |  326 lines

  1. /* This file is part of 'minixfs' Copyright 1991,1992,1993 S.N. Henson */
  2.  
  3. #include "minixfs.h"
  4. #include "global.h"
  5. #include "proto.h"
  6.  
  7. /* For this kind of file system a cache is absolutely essential ,
  8. without it your hard-disk will sound like a buzz-saw .... the 
  9. idea is fairly simple , for every block requested if it is not in 
  10. the cache load it in at the current position .Then return a 
  11. pointer to the block . Additionally all writes go to the cache if
  12. an entry exists for the specified block . This means that when a 
  13. cache entry is overwritten we must write out the entry if it is
  14. 'dirty' , the function l_sync() writes out the entire cache along
  15. with the zone and inode bitmaps. All functions , except write , call
  16. l_sync() on each call . Write calls l_sync() only after a certain
  17. amount of data has been written , this stops lots of little writes
  18. taking too much time .... However for an increase in performance , 
  19. three caches are used , one for inodes one for directories and indirection 
  20. blocks , one for files , these are kmalloc()'ed at the same time so that 
  21. one follows the other in memory , this simplifies cache-flushing for example.
  22. */
  23.  
  24. /* Initialise cache */
  25. int init_cache()
  26. {
  27.     cache *ctemp;
  28.     long i;
  29.         /* Start with system cache */
  30.     ctemp=Kmalloc((icache_size+scache_size+ucache_size)*(SIZEOF(cache)+BLOCK_SIZE));
  31.     if(!ctemp)
  32.     {
  33.         CCONWS("Can't Allocate Cache: Using defaults");
  34.         ctemp=Kmalloc((ICACHE_SIZE+SCACHE_SIZE+UCACHE_SIZE)*(SIZEOF(cache)+BLOCK_SIZE));
  35.         if(!ctemp)
  36.         {
  37.             CCONWS("Can't Allocate Default Cache: Minixfs not installed");
  38.             return 1;
  39.         }
  40.         icache_size=ICACHE_SIZE;
  41.         ucache_size=UCACHE_SIZE;
  42.         scache_size=SCACHE_SIZE;
  43.     }
  44.  
  45.     syscache.start=ctemp;
  46.     syscache.end=&ctemp[scache_size];
  47.     syscache.pos=syscache.start;
  48.     icache.start=syscache.end;
  49.     icache.end=&icache.start[icache_size];
  50.     icache.pos=icache.start;
  51.     usrcache.start=icache.end;
  52.     usrcache.pos=usrcache.start;
  53.     usrcache.end=&usrcache.start[ucache_size];
  54.     /* Invalidate all entries , initialise buffer pointers */
  55.     for(ctemp=syscache.start,i=0;ctemp!=usrcache.end;ctemp++,i++)
  56.     {
  57.         ctemp->buffer= ((bufr *)(usrcache.end))+i;
  58.         ctemp->status=0;
  59.     }
  60.  
  61. /* Initialise dummy guess */
  62.     dummy.iguess=icache.start;
  63.     dummy.zguess=usrcache.start;
  64.     dummy.izguess=syscache.start;
  65.     dummy.dizguess=syscache.start;
  66.  
  67.     return 0;
  68. }
  69.  
  70.  
  71. void
  72. l_sync()
  73. {
  74.     cache *p;
  75.     int i;
  76. /* Write out dirty cache entries */
  77.     for(p=syscache.start;p!=usrcache.end;p+=writeout(&usrcache,p)) continue;
  78.  
  79.     /* Now inode and zone bitmaps */
  80.     for(i=0;i<NUM_DRIVES;i++)
  81.     {
  82.     if(super_ptr[i]) {
  83.         super_info *psblk;
  84.         psblk=super_ptr[i];
  85.         if(psblk==DFS) continue;
  86.  
  87.         if(psblk->idirty && psblk->zdirty)
  88.             crwabs(3,psblk->ibitmap,psblk->sblk.s_imap_blks+
  89.                 psblk->sblk.s_zmap_blks,2,i);
  90.         else
  91.         {
  92.             if(psblk->idirty)
  93.                crwabs(3,psblk->ibitmap,psblk->sblk.s_imap_blks,2,i);
  94.              if(psblk->zdirty)
  95.                  crwabs(3,psblk->zbitmap,psblk->sblk.s_zmap_blks,
  96.                            psblk->sblk.s_imap_blks+2,i);
  97.         }
  98.         psblk->idirty=0;
  99.         psblk->zdirty=0;
  100.     }
  101.     }
  102. }
  103.  
  104. /* Return cache entry for numr,drive if it exists or NULL, this uses a 'guess'
  105.  * pointer for the caches: start at the point an entry was last found, this
  106.  * should be reduce cache searching a bit.
  107.  */
  108.  
  109. cache *in_cache(numr,drive,control,guess)
  110. long numr;
  111. int drive;
  112. cache_control *control;
  113. cache **guess;
  114. {
  115.     cache *p;
  116.  
  117.     if(guess)
  118.     {
  119.  
  120.         for(p=*guess;p!=control->end;p++)
  121.             if((p->block==numr) && (p->drive==drive) && p->status)
  122.                             return (*guess=p);
  123.         for(p=control->start;p!=*guess;p++)
  124.             if((p->block==numr) && (p->drive==drive) && p->status)
  125.                             return (*guess=p);
  126.     }
  127.     else
  128.     {
  129.         for(p=control->start;p!=control->end;p++)
  130.             if((p->block==numr) && (p->drive==drive) && p->status)
  131.                             return p;
  132.     }
  133.  
  134.     return NULL;
  135. }
  136.  
  137. /* Return a pointer to block numr,drive loading and updating cache if needed */
  138.  
  139. bufr *cget_block(numr,drive,control)
  140. long numr;
  141. int drive;
  142. cache_control * control;
  143. {
  144.     return(cache_get(numr,drive,control,NOGUESS)->buffer);
  145. }
  146.  
  147. /* Return a pointer to a cache entry buffer for numr,drive with the dirty 
  148.  * flag set, if not in cache create a new entry but do *not* read in data
  149.  * from the disk, this is useful for example when an entire disk block will
  150.  * be written in one go.
  151.  */
  152.  
  153. cache *cache_put(numr,drive,control)
  154. long numr;
  155. int drive;
  156. cache_control *control;
  157. {
  158.     cache *p;
  159.     if(!(p=in_cache(numr,drive,control,NOGUESS)))
  160.     {
  161.         if(control!=&icache) chk_zone(numr,1,drive);
  162.         if(control->pos==control->end) control->pos=control->start;
  163.         p=control->pos++;
  164.         writeout(control,p);
  165.         p->drive=drive;
  166.         p->block=numr;
  167.     }
  168.  
  169.     p->status=2;
  170.     return (p);
  171. }
  172.  
  173. cache *
  174. cache_get(numr,drive,control,guess)
  175. long numr;
  176. int drive;
  177. cache_control *control;
  178. cache **guess;
  179. {
  180.     cache *p;
  181.     if( (p=in_cache(numr,drive,control,guess)) )return(p);
  182.     /* Read block in */
  183.     if(control->pos==control->end)
  184.         control->pos=control->start;
  185.     /* Write out dirty entries before they are overwritten */
  186.     if(control->pos->status >1 ) writeout(control,control->pos);
  187.  
  188.     /* This is the only check done on I/O into cache. If invalid
  189.      * blocks can never enter the cache then all should be OK
  190.      * later on. Unless the memory gets trashed. Interesting hack:
  191.      * if iblock is in range and all inode blocks are used (as will
  192.      * usually be the case) then the inode number producing it should
  193.      * be in range too, so no checking on inode numbers need be done.
  194.      */
  195.  
  196.     if(control==&icache) chk_iblock(numr,super_ptr[drive]);
  197.     else chk_zone(numr,1,drive) ;
  198.  
  199.  
  200.     crwabs(2,control->pos->buffer,1,numr,drive);
  201.     /* Update Cache */
  202.     control->pos->drive=drive;
  203.     control->pos->block=numr;
  204.     control->pos->status=1;
  205.  
  206.     if(guess) *guess=control->pos;
  207.     return ( control->pos++ );
  208. }
  209.  
  210. /* Write out block, search cache and if 'hit' update and mark as dirty 
  211.  * after copying the data across, otherwise flush current entry.
  212.  */
  213.  
  214. int
  215. cput_block(numr,drive,buf,control)
  216. long numr;
  217. int drive;
  218. void *buf;
  219. cache_control *control;
  220. {
  221.     cache *p;
  222.  
  223.     if( (p=in_cache(numr,drive,control,NOGUESS)) ){
  224.         if(buf!=p->buffer) bcopy(buf,p->buffer,BLOCK_SIZE);
  225.         p->status=2;
  226.         return 0;
  227.     }
  228.  
  229.     if(control->pos==control->end) control->pos=control->start;
  230.     writeout(control,control->pos);
  231.  
  232.     if(control!=&icache) chk_zone(numr,1,drive);
  233.  
  234.     bcopy(buf,control->pos->buffer,BLOCK_SIZE);
  235.     /* Update Cache */
  236.     control->pos->drive=drive;
  237.     control->pos->block=numr;
  238.     control->pos->status=2;
  239.     control->pos++;
  240.     return 0;
  241. }
  242.  
  243. /* From the cache-pointer 'p' write out dirty entries that are consecutive
  244.  * all in one go, this should cut down on I/O quite a lot.
  245.  */
  246.  
  247. long writeout(control,p)
  248. cache_control *control;
  249. cache *p;
  250. {
  251.     cache *q;
  252.     long i;
  253.  
  254.     if(p->status<2) return 1;
  255.     /* Determined how many blocks are consecutive */
  256.     for(q=p,i=0;q!=control->end;q++,i++)
  257.     {
  258.         if( (q->drive!=p->drive) || (q->block!=p->block+i) || 
  259.             (q->status < 2) ) break;
  260.         q->status=1;
  261.     }
  262.  
  263.     crwabs(3,p->buffer,i,p->block,p->drive);
  264.  
  265.     return i;
  266. }
  267.  
  268. /* From the current cache position, read up to the num zones pointed to by
  269.  * zone_list in. Flush the cache and read in as much as possible in one go.
  270.  * Stop at first non-consecutive zone.
  271.  */
  272.  
  273. long readin(zone_list,num,drive,control)
  274. long *zone_list;
  275. int num;
  276. int drive;
  277. cache_control *control;
  278. {
  279.     cache *p;
  280.     int i,j;
  281.  
  282.     if(!*zone_list) return 0;
  283.     for(i=1;i<num;i++)if(zone_list[i]!=zone_list[0]+i) break;
  284.     if(control->pos==control->end) control->pos=control->start;
  285.     i=min(control->end-control->pos,i);
  286.     /* If any entries already in cache, forget it */
  287.     for(p=control->start;p!=control->end;p++) if( (p->drive==drive) 
  288.     && (p->block >= zone_list[0]) && (p->block < zone_list[0]+i) ) 
  289.         return 0;
  290.  
  291.     /* Write out at least 'i' entries */
  292.     for(p=control->pos; p < control->pos+i ; )
  293.     {
  294.         if(p->status < 2) p++;
  295.         else p+=writeout(control,p);
  296.     }
  297.  
  298.     chk_zone(zone_list[0],i,drive);
  299.  
  300.     crwabs(2,control->pos->buffer,i,zone_list[0],drive);
  301.     for(p=control->pos,j=0;j<i;j++,p++)
  302.     {
  303.         p->block=zone_list[j];
  304.         p->drive=drive;
  305.         p->status=1;
  306.     }
  307.     control->pos+=i;
  308.     return i;
  309. }
  310.  
  311. /* Invalidate all cache entries for a given drive */
  312.  
  313. void m_invalidate(drv)
  314. int drv;
  315. {
  316.     int warned=0;
  317.     cache *p;
  318.     for(p=syscache.start;p!=usrcache.end;p++)
  319.     if(p->drive==drv && p->status)
  320.     {
  321.         if(p->status==2 && !warned++)
  322.         ALERT("Cache entry not written out when drive %c invalidated",drv+'A');
  323.         p->status=0;
  324.     }
  325. }
  326.